		;; Here are the code of bootloader of EKOS-CC

		;; the macro defines a segment descriptor
%macro segdesc 3
		;; %1: type
		;; %2: base
		;; %3: limit

		dw (%3 >> 12) & 0xffff
		dw (%2) & 0xffff
		db (%2 >> 16) & 0xff
		db (%1) | 0x90
		db ((%3 >> 28) & 0xf) | 0xC0
		db (%2 >> 24) & 0xff
%endmacro
		
		;; Specify the starting address as 0x7c00
		org 0x7c00
		;; We start in 16-bits mode
		bits 16
section .code
		
start:
		;; Here the boot sector code begins

		;; Invoke the interruption to detect the memory layout, then
		;; store the layout table

	    xor ax, ax
	    mov es, ax
	    mov di, 0x100c

	    ;; ebx must be 0 to start
	    xor ebx, ebx
	    ;; keep an entry count in bp
	    xor ebp, ebp
	    ;; Place "SMAP" into edx
		
	    mov edx, 0x0534D4150
	    mov eax, 0xe820
	    ;; force a valid ACPI 3.X entry
	    mov dword [es:di+20], 1
	    ;; ask for 24 bytes
	    mov ecx, 24
		
	    int 0x15
	    ;; carry set on first call means "unsupported function"
	    jc mm_failed
	    ;; Some BIOSes apparently trash this register?
	    mov edx, 0x0534D4150
	    ;; on success, eax must have been reset to "SMAP"
	    cmp eax, edx
	    jne mm_failed
	    ;; ebx = 0 implies list is only 1 entry long (worthless)
	    test ebx, ebx
	    je mm_failed
	    jmp mm_jmpin
mm_e820lp:
	    ;; eax, ecx get trashed on every int 0x15 call
	    mov eax, 0xe820
	    ;; force a valid ACPI 3.X entry
	    mov dword [es:di + 20], 1
	    ;; ask for 24 bytes again
	    mov ecx, 24
	    int 0x15
	    ;; carry set means "end of list already reached"
	    jc mm_e820f
	    ;; repair potentially trashed register
	    mov edx, 0x0534D4150
mm_jmpin:
	    ;; skip any 0 length entries
	    jcxz mm_skipent
	    ;; got a 24 byte ACPI 3.X response?
	    cmp cl, 20
	    jbe mm_notext
	    ;; if so: is the "ignore this data" bit clear?
	    test byte [es:di + 20], 1 
	    je mm_skipent
mm_notext:
	    ;; get lower dword of memory region length
	    mov ecx, [es:di + 8], 
	    ;; is the qword == 0?
	    test ecx, ecx
	    jne mm_goodent
	    ;; get upper dword of memory region length
	    mov ecx, [es:di + 12]
	    ;; if length qword is 0, skip entry
	    jecxz mm_skipent
mm_goodent:
	    ;; got a good entry: ++count, move to next storage spot
	    inc ebp
	    add di, 24
mm_skipent:
	    ;; if ebx resets to 0, list is complete
	    test ebx, ebx
	    jne mm_e820lp
mm_e820f:
	    ;; store the entry count
	    mov [es:0x1008], ebp, 
	    ;; test opcode cleared carry flag
	    jmp mm_exit
mm_failed:
	    ;;    "function unsupported" error exit
		mov dword [es:0x1008], 0
mm_exit:
		
		;; Trying to get into protected mode
		cli
		cld

		;; Clear the segment register
		xor ax, ax
		mov ds, ax
		mov es, ax
		mov ss, ax

seta20_1:
		;; Wait for not busy
	    in al, 0x64
	    test al, 0x2
	    jnz seta20_1

		;;  0xd1 -> port 0x64
	    mov al, 0xd1			
	    out 0x64, al

seta20_2:
		;; Wait for not busy
		in al, 0x64
	    test al, 0x2
	    jnz seta20_2
		
		;; 0xdf -> port 0x60
	    mov al, 0xdf
	    out 0x60, al
		
		;; Switch from real to protected mode, using a bootstrap GDT
		;; and segment translation that makes virtual addresses
		;; identical to their physical addresses, so that the
		;; effective memory map does not change during the switch.
		
	    lgdt [bootloader_gdtdesc]
	    mov eax, cr0
		;; Set the PE flag on
	    or eax, 0x1
	    mov cr0, eax
		;; 0x8 is the segment of code
		jmp 0x8:pmode_start

		bits 32

pmode_start:
		;; Initialize the segment register
		mov ax, 0x10
		mov ds, ax
		mov es, ax
		mov fs, ax
		mov gs, ax
		
		;; Set the stack pointer
		mov ss, ax
		mov ebp, 0
		mov esp, start

		call waitdisk

		;; Read the stage 1 binary from disk
		mov dx, 0x1f2
	    mov ax, STAGE1_SECT_COUNT
		xor ebx, ebx
		mov bx, ax
		mov dword[es:0x1000], ebx
	    out dx, al
		;; stage 1 start from sector 1
	    mov eax, STAGE1_SECT_OFFSET
		mov dword[es:0x1004], eax
		
	    inc dx
	    out dx, al
	    shr eax, 8
		
	    inc dx
	    out dx, al
	    shr eax, 8

		inc dx
	    out dx, al
	    shr eax, 8 

	    or al, 0xe0
	    inc dx
	    out dx, al

	    mov al, 0x20
	    inc dx
	    out dx, al

		;; edi is the dest address
		mov edi, STAGE1_START
		jmp readsect_loop

		;; Wait for disk ready
waitdisk:
	    mov  dx, 0x1f7
waitdisk_1:
	    in al, dx
	    and al, 0xc0
	    cmp al, 0x40
	    jne waitdisk_1
	    ret

readsect_loop:
	    call  waitdisk
		
	    mov  dx, 0x1f0
	    cld
		
	    mov  ecx, 0x80
	    repnz insd

	    dec bx
	    jnz readsect_loop

		;; Get into the stage 1
		mov eax, STAGE1_START
		jmp eax
		
pmode_loop:		
		;; SELF LOOP
		jmp pmode_loop

		align 4
		
bootloader_gdt:
		;; null desc
		dd 0, 0
		;; 4g code seg, r/x
		segdesc 0x2 | 0x8, 0, 0xffffffff
		;; 4g data seg, r/w
		segdesc 0x2, 0, 0xffffffff

bootloader_gdtdesc:
		;; sizeof(gdt) - 1
	    dw 0x17
		;; address gdt
	    dd bootloader_gdt
